﻿using System;
using System.Collections.Generic;
using FrameDesign.FrameWork.Command;
using FrameWorkDesign.Example.Event;

namespace FrameDesign.FrameWork
{
    public interface IArchitecture
    {
        /// <summary>
        /// 注册 Model
        /// </summary>
        void RegisterModel<T>(T instance) where T: IModel;

        /// <summary>
        /// 注册 Utility
        /// </summary>
        void RegisterUtility<T>(T instance);

        /// <summary>
        /// 注册系统
        /// </summary>
        void RegisterSystem<T>(T instance) where T: ISystem;
        /// <summary>
        /// 获取 System
        /// </summary>
        T GetSystem<T>() where T: class, ISystem; // 新增
        /// <summary>
        /// 获取工具
        /// </summary>
        T GetUtility<T>() where T: class;
        /// <summary>
        /// 获取 Model（System 层中有可能直接访问 Model 层）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetModel<T>() where T: class, IModel;
        /// <summary>
        /// 发送命令
        /// </summary>
        void SendCommand<T>() where T: ICommand, new(); // 新增

        /// <summary>
        /// 发送命令
        /// </summary>
        void SendCommand<T>(T command) where T: ICommand; // 新增
        
        /// <summary>
        /// 发送事件
        /// </summary>
        void SendEvent<T>() where T : new(); // +

        /// <summary>
        /// 发送事件
        /// </summary>
        void SendEvent<T>(T e); // +

        /// <summary>
        /// 注册事件
        /// </summary>
        IUnRegister RegisterEvent<T>(Action<T> onEvent); // +

        /// <summary>
        /// 注销事件
        /// </summary>
        void UnRegisterEvent<T>(Action<T> onEvent); // +
    }
    /// <summary>
    /// 架构
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Architecture<T> : IArchitecture where T: Architecture<T>, new()
    {
        /// <summary>
        /// 注册补丁
        /// </summary>
        public static Action<T> OnRegisterPatch = architecture =>
        {
        };
        /// <summary>
        /// 是否已经初始化完成
        /// </summary>
        private bool mInited = false;

        /// <summary>
        /// 用于初始化的 Models 的缓存
        /// </summary>
        private List<IModel> mModels = new List<IModel>();
        /// <summary>
        /// 用于初始化的 Systems 的缓存
        /// </summary>
        private List<ISystem> mSystems = new List<ISystem>();

        private static T m_Architecture;

        // 新增
        public static IArchitecture Interface
        {
            get
            {
                if (m_Architecture == null)
                {
                    MakeSureArchitecture();
                }

                return m_Architecture;
            }
        }

        /// <summary>
        /// 注册实例
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        public static void Register<T>(T instance)
        {
            MakeSureArchitecture();
            m_Architecture.m_IOCContainer.Register<T>(instance);
        }
        public void RegisterUtility<T>(T instance)
        {
            m_IOCContainer.Register<T>(instance);
        }
        /// <summary>
        /// 提供一个注册 Model 的 API
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        public void RegisterModel<T>(T instance) where T: IModel
        {
            // 需要给 Model 赋值一下
            instance.SetArchitecture(this); // 修改
            m_IOCContainer.Register<T>(instance);
            // 如果初始化过了
            if (mInited)
            {
                instance.Init();
            }
            else
            {
                // 添加到 Model 缓存中，用于初始化
                mModels.Add(instance);
            }
        }

        /// <summary>
        /// 提供一个注册 Model 的 API
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        public void RegisterSystem<T>(T instance) where T: ISystem
        {
            // 需要给 System 赋值一下
            instance.SetArchitecture(this); // 修改
            m_IOCContainer.Register<T>(instance);

            // 如果初始化过了
            if (mInited)
            {
                instance.Init();
            }
            else
            {
                // 添加到 Model 缓存中，用于初始化
                mSystems.Add(instance);
            }
        }
        /// <summary>
        /// 确保 Container 是有实例的
        /// </summary>
        static void MakeSureArchitecture()
        {
            if (m_Architecture == null)
            {
                m_Architecture = new T();
                m_Architecture.Init();
                // 调用
                OnRegisterPatch?.Invoke(m_Architecture);
                // 初始化 Model
                foreach (var architectureModel in m_Architecture.mModels)
                {
                    architectureModel.Init();
                }

                // 清空 Model
                m_Architecture.mModels.Clear();
                // 初始化 System

                foreach (var architectureSystem in m_Architecture.mSystems) // 新增
                {
                    architectureSystem.Init();
                }

                // 清空 System
                m_Architecture.mSystems.Clear(); // 新增
                m_Architecture.mInited = true;
            }
        }
        /// <summary>
        /// IOC容器
        /// </summary>
        private IOCContainer m_IOCContainer = new IOCContainer();

        /// <summary>
        /// 留给子类注册模块
        /// </summary>
        protected abstract void Init();

        public void SendCommand<T>() where T: ICommand, new() // 新增
        {
            var command = new T();
            command.SetArchitecture(this);
            command.Execute();
        }

        public void SendCommand<T>(T command) where T: ICommand // 新增
        {
            command.SetArchitecture(this);
            command.Execute();
        }
        // 新增
        public T GetUtility<T>() where T: class
        {
            return m_IOCContainer.Get<T>();
        }
        public T GetModel<T>() where T: class, IModel
        {
            return m_IOCContainer.Get<T>();
        }
        public T GetSystem<T>() where T: class, ISystem // 新增
        {
            return m_IOCContainer.Get<T>();
        }
        
        private ITypeEventSystem mTypeEventSystem = new TypeEventSystem(); // +

        public void SendEvent<T>() where T : new() // +
        {
            mTypeEventSystem.Send<T>();
        }

        public void SendEvent<T>(T e) // +
        {
            mTypeEventSystem.Send<T>(e);
        }

        public IUnRegister RegisterEvent<T>(Action<T> onEvent) // +
        {
            return mTypeEventSystem.Register<T>(onEvent);
        }

        public void UnRegisterEvent<T>(Action<T> onEvent) // +
        {
            mTypeEventSystem.UnRegister<T>(onEvent);
        }
    }
}